<template>
  <div class="weekly-view">
    <div class="card">
      <div class="calendar-header">
        <div>
          <el-radio-group
            v-model="viewType"
            size="mini"
            @input="handleViewTypeChange"
          >
            <el-radio-button
              :label="viewTypeMap.TIME_GRID_WEEK"
            >
              周
            </el-radio-button>

            <el-radio-button
              :label="viewTypeMap.TIME_GRID_DAY"
            >
              日
            </el-radio-button>
          </el-radio-group>

          <el-select
            v-model="params.id"
            placeholder="请选择会议室"
            clearable
            size="mini"
            style="margin-left: 10px;"
            @change="handleRoomChange"
          >
            <el-option
              v-for="item in conferenceRoomList"
              :key="item.id"
              :label="item.name"
              :value="item.id"
            />
          </el-select>
        </div>

        <div class="calendar-header__title">
          {{ calendarTitle }}
        </div>

        <div>
          <el-button
            size="mini"
            type="primary"
            @click="handleChangeDate('prev')"
          >
            {{ prevBtnText }}
          </el-button>

          <el-button
            size="mini"
            @click="handleBackToday"
          >
            {{ viewType === viewTypeMap.TIME_GRID_WEEK ? '回到本周' : '回到今天' }}
          </el-button>

          <el-button
            size="mini"
            type="primary"
            @click="handleChangeDate('next')"
          >
            {{ nextBtnText }}
          </el-button>
        </div>
      </div>

      <div class="flex item-center" style="margin-bottom: 20px;">
        <div
          v-for="(tips, index) in stateColorTips"
          :key="index"
          class="flex item-center tips-item"
        >
          <div
            class="rectangle"
            :style="{
              backgroundColor: tips.color
            }"
          />
          <div style="margin-left: 5px;">{{ tips.title }}</div>
        </div>

      </div>
      <div
        v-loading="loading"
      >
        <FullCalendar
          ref="fullCalendar"
          :options="calendarOptions"
        >
          <template #eventContent="{ event }">
            <div
              class="event-content"
              :style="{
                'background-color': event.extendedProps.customBgColor
              }"
            >
              <div>
                {{ generateEventTime(event.start, event.end) }}
              </div>
              <div>预约原因：{{ event.title }}</div>
              <div>会议室：{{ event.extendedProps.roomName }}</div>
              <div>预约人：{{ event.extendedProps.userName }}</div>
            </div>
          </template>
        </FullCalendar>
      </div>
    </div>
  </div>
</template>
<script>
import FullCalendar from '@fullcalendar/vue'
import dayGridPlugin from '@fullcalendar/daygrid'
import timeGridPlulgin from '@fullcalendar/timegrid'
import '@fullcalendar/core/locales/zh-cn'
import interactionPlugin from '@fullcalendar/interaction'
import dayjs from 'dayjs'
import { getConferenceRoomList, getReserveRecords } from '@/api/conferenceRoom'
import { WebSocketClient } from '@/utils/webSocket'
import { bind } from '@/api/v2/visitor'

const TIME_GRID_DAY = 'dayGrid'
const TIME_GRID_WEEK = 'dayGridWeek'
export default {
  name: '',
  components: {
    FullCalendar
  },
  data() {
    return {
      viewType: 'dayGridWeek',
      calendarTitle: '',
      conferenceRoomList: [],
      params: {
        id: null,
        state: 'success',
        time: []
      },
      list: [],
      loading: false,
      timer: null,
      socketClient: null
    }
  },
  computed: {
    calendarOptions() {
      return {
        contentHeight: '80vh',
        initialView: 'dayGridWeek',
        plugins: [dayGridPlugin, timeGridPlulgin, interactionPlugin],
        allDaySlot: false,
        initialDate: new Date(),
        axisFormat: 'h(:mm)tt',
        locale: 'zh-cn',
        // dayMaxEvents: this.dayMaxValEvents,
        headerToolbar: null,
        // headerToolbar: {
        //   left: 'prev,next today',
        //   center: 'title',
        //   right: 'dayGridMonth,timeGridWeek,timeGridDay'
        // },
        // 最小时间
        slotMinTime: '08:00:00',
        // 最大时间
        slotMaxTime: '18:00:00',
        handleWindowResize: true,
        weekNumberCalculation: 'ISO'
      }
    },

    dayMaxValEvents() {
      switch (this.viewType) {
        case TIME_GRID_WEEK:
          return 5

        case TIME_GRID_DAY:
          return 6

        default:
          return 5
      }
    },

    prevBtnText() {
      return this.viewType === TIME_GRID_WEEK ? '上一周' : '上一天'
    },

    nextBtnText() {
      return this.viewType === TIME_GRID_WEEK ? '下一周' : '下一天'
    },

    viewTypeMap() {
      return {
        TIME_GRID_DAY,
        TIME_GRID_WEEK
      }
    },

    stateColorMap() {
      return {
        done: '#F56C6C',
        pending: '#409EFF',
        inProgress: '#67C23A'
      }
    },

    stateColorTips() {
      return [
        { title: '未开始', color: this.stateColorMap.pending },
        { title: '进行中', color: this.stateColorMap.inProgress },
        { title: '已结束', color: this.stateColorMap.done }
      ]
    }
  },

  mounted() {
    this.connectWebSocket()
    this.generateTitle()
    this.getList()
    this.getConferenceRoomList()
    this.refreshStatus()
    this.socketClient.wsIsInlineChecker()
  },

  beforeDestroy() {
    this.socketClient.close()
    this.socketClient.stopWsChecker()
  },

  destroyed() {
    clearInterval(this.timer)
  },

  methods: {
    connectWebSocket() {
      this.socketClient = new WebSocketClient(process.env.VUE_APP_WS_URL)

      this.socketClient.connect()

      this.socketClient.onMessage = this.onMessage
    },

    async onMessage(data) {
      console.log('data --------->', data)
      switch (data.type) {
        case 'sendMessage':
          break

        case 'bind':
          await this.bindClient('bind', data.data)
          break

        case 'refresh':
          await this.getList()
          break
      }
    },

    async bindClient(type, data) {
      await bind({ type, client_id: data }).catch((e) => {
        throw new Error(e?.response?.data?.message ?? '绑定失败')
      })
      // this.saveStorages()
    },

    async getConferenceRoomList() {
      try {
        const { data } = await getConferenceRoomList()
        this.conferenceRoomList = data
      } catch (error) {
        this.$message.error('获取会议室列表失败')
      }
    },

    async getList() {
      this.loading = true
      try {
        const res = await getReserveRecords({
          ...this.params,
          time: this.params.time && this.params.time.length ? JSON.stringify(this.params.time) : null
        })
        this.list = res.data.map(item => {
          const roomInfo = JSON.parse(item.room)
          return {
            ...item,
            room_name: roomInfo.name,
            room: roomInfo
          }
        })

        this.addEvent(this.list)
      } catch (error) {
        console.log('error --------->', error)
        this.$message.error('获取预约记录失败')
      } finally {
        this.loading = false
      }
    },

    generateTitle() {
      if (this.viewType === TIME_GRID_WEEK) {
        const { start, end } = this.getWeekRange()

        const startDate = `${start.year}年${start.month}月${start.day}日`

        const endDate = start.year === end.year ? `${end.day}日`
          : `${end.year}年${end.month}月${end.day}日`

        this.calendarTitle = `${startDate}-${endDate}`
      } else if (this.viewType === TIME_GRID_DAY) {
        const { year, month, day } = this.getWeekRange()

        this.calendarTitle = `${year}年${month}月${day}日`
      }
    },

    handleChangeDate(action) {
      this.$refs.fullCalendar.getApi()[action]()
      this.updateData()
    },

    handleViewTypeChange() {
      this.$refs.fullCalendar.getApi().changeView(this.viewType)
      this.updateData()
    },

    handleBackToday() {
      this.$refs.fullCalendar.getApi().today()
      this.updateData()
    },

    handleRoomChange() {
      this.getList()
    },

    updateData() {
      this.list = []
      this.generateTitle()
      this.getList()
    },

    getStatusColor(start, end) {
      const now = dayjs()
      const startTime = dayjs(start)
      const endTime = dayjs(end)

      if (now.isBefore(startTime)) {
        return this.stateColorMap.pending // 未开始
      } else if (now.isAfter(endTime)) {
        return this.stateColorMap.done // 已结束
      } else {
        return this.stateColorMap.inProgress // 正在进行中
      }
    },

    addEvent(eventList) {
      this.$refs.fullCalendar.getApi().removeAllEvents()
      eventList.forEach(item => {
        this.$refs.fullCalendar.getApi().addEvent({
          title: item?.reason,
          roomName: item?.room?.name,
          userName: item?.user?.username,
          start: item?.start_time,
          end: item?.end_time,
          customBgColor: this.getStatusColor(item.start_time, item.end_time)
        })
      })
    },

    generateEventTime(start, end) {
      const startTime = dayjs(start)
      const endTime = dayjs(end)

      const startHour = startTime.hour() > 10
        ? startTime.hour() : `0${startTime.hour()}`

      const startMinute = startTime.minute() > 10
        ? startTime.minute() : `0${startTime.minute()}`

      const endHour = endTime.hour() > 10
        ? endTime.hour() : `0${endTime.hour()}`

      const endMinute = endTime.minute() > 10
        ? endTime.minute() : `0${endTime.minute()}`

      return `${startHour}:${startMinute}~${endHour}:${endMinute}`
    },

    refreshStatus() {
      clearInterval(this.timer)
      this.timer = setInterval(() => {
        this.getList()
      }, 5 * 60 * 1000)
    },

    getWeekRange() {
      if (this.viewType === TIME_GRID_WEEK) {
        const time = dayjs(this.$refs.fullCalendar.getApi().getDate()).format('YYYY-MM-DD')

        const date = dayjs(time)
        const currentDayOfWeek = date.day()

        const startOfWeekMonday = currentDayOfWeek === 0
          ? date.subtract(6, 'day').startOf('day') // 如果是周日，需要减去 6 天
          : date.subtract(currentDayOfWeek - 1, 'day').startOf('day')

        const endOfWeekSunday = currentDayOfWeek === 0
          ? date.endOf('day')
          : date.add(7 - currentDayOfWeek, 'day').endOf('day')

        this.params.time = [
          startOfWeekMonday.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
          endOfWeekSunday.endOf('day').format('YYYY-MM-DD HH:mm:ss')
        ]

        const yearStart = startOfWeekMonday.year()

        const monthStart = startOfWeekMonday.month() + 1 >= 10
          ? startOfWeekMonday.month() + 1 : `0${startOfWeekMonday.month() + 1}`

        const dayStart = startOfWeekMonday.date() >= 10
          ? startOfWeekMonday.date() : `0${startOfWeekMonday.date()}`

        const yearEnd = endOfWeekSunday.year()

        const monthEnd = endOfWeekSunday.month() + 1 >= 10
          ? endOfWeekSunday.month() + 1 : `0${endOfWeekSunday.month() + 1}`

        const dayEnd = endOfWeekSunday.date() >= 10
          ? endOfWeekSunday.date() : `0${endOfWeekSunday.date()}`

        return {
          start: { year: yearStart, month: monthStart, day: dayStart },
          end: { year: yearEnd, month: monthEnd, day: dayEnd }
        }
      } else if (this.viewType === TIME_GRID_DAY) {
        const t = dayjs(this.$refs.fullCalendar.getApi().getDate())

        this.params.time = [
          t.startOf('day').format('YYYY-MM-DD HH:mm:ss'),
          t.endOf('day').format('YYYY-MM-DD HH:mm:ss')
        ]

        const year = t.year()

        const month = t.month() + 1 >= 10
          ? t.month() + 1 : `0${t.month() + 1}`

        const day = t.date() >= 10
          ? t.date() : `0${t.date()}`

        return {
          year, month, day
        }
      }
    }
  }
}
</script>
<style lang="scss" scoped>
.weekly-view {
  padding: 20px;
  background-color: #F5F5F5;
  //min-height: calc(100vh - 104px);

  .calendar-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 20px;

    &__title {
      font-size: 28px;
      font-weight: bold;
    }
  }

  .event-content {
    width: 100%;
    padding: 10px;
    color: #fff;
    margin: 5px 10px;

    > div {
      margin-bottom: 5px;

      &:last-child {
        margin-bottom: 0;
      }
    }
  }

  .tips-item {
    font-size: 14px;
    margin-right: 15px;

    &:last-child {
      margin-right: 0;
    }
  }

  .rectangle {
    width: 15px;
    height: 15px;
  }

  ::v-deep(.fc-header-toolbar) {
    margin-bottom: 0;
  }

  ::v-deep(.fc-day-today) {
    background-color: transparent;
  }

  ::v-deep(.fc-daygrid-day-bottom) {

    > a {
      display: block;
      margin-top: 4px;
      padding: 10px;
      border: 1px solid #bdbdbd;
      width: 100%;
      text-align: center;
    }
  }

  ::v-deep(.fc-daygrid-dot-event:hover) {
    background: transparent;
  }
}
</style>
